from flask import Flask, request, jsonify 
from datetime import datetime 
import time 
import sqlite3 
import socket 
import netifaces 
import os 
import random 
from threading import Lock 
 
app = Flask(__name__)
db_lock = Lock()
 
# 配置 
CONFIG = {
    'predefined_ips': ['192.168.1.60', '192.168.1.61'],
    'port': 5000,
    'autodetect_ips': True,
    'user_id_length': 10,
    'message_cache_size': 100 
}
 
# 生成随机用户ID 
def generate_user_id():
    return ''.join([str(random.randint(0, 9)) for _ in range(CONFIG['user_id_length'])])
 
# 获取所有可用的局域网IP 
def get_all_local_ips():
    ips = CONFIG['predefined_ips'].copy()
    
    if CONFIG['autodetect_ips']:
        try:
            for interface in netifaces.interfaces():
                addrs = netifaces.ifaddresses(interface)
                if netifaces.AF_INET in addrs:
                    for addr in addrs[netifaces.AF_INET]:
                        ip = addr['addr']
                        if ip != '127.0.0.1' and not ip.startswith('169.254'):
                            ips.append(ip)
        except:
            pass 
    
    seen = set()
    return [ip for ip in ips if not (ip in seen or seen.add(ip))]
 
# 数据库初始化 
def init_db():
    if os.path.exists('chat.db'):
        os.remove('chat.db')
    
    with sqlite3.connect('chat.db') as conn:
        c = conn.cursor()
        c.execute('''CREATE TABLE users 
                     (id TEXT PRIMARY KEY,
                      device_info TEXT,
                      ip TEXT,
                      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                      last_active TIMESTAMP)''')
        
        c.execute('''CREATE TABLE messages 
                     (id INTEGER PRIMARY KEY AUTOINCREMENT,
                      sender TEXT,
                      text TEXT,
                      time TEXT,
                      timestamp REAL,
                      FOREIGN KEY(sender) REFERENCES users(id))''')
        
        c.execute('CREATE INDEX idx_messages_timestamp ON messages(timestamp)')
        c.execute('CREATE INDEX idx_messages_sender ON messages(sender)')
        c.execute('CREATE INDEX idx_users_last_active ON users(last_active)')
        conn.commit()
 
@app.route('/')
def index():
    return "聊天服务器已运行！访问 /register 注册用户"
 
@app.route('/ping', methods=['GET'])
def ping():
    return jsonify({
        'service': 'chat_server',
        'version': '1.0',
        'server_ips': get_all_local_ips(),
        'timestamp': time.time()
    })
 
@app.route('/register', methods=['POST'])
def register_user():
    data = request.json 
    if not data:
        return jsonify({'status': 'error', 'message': 'No data provided'}), 400 
    
    device_info = data.get('device_info', 'unknown')
    ip = request.remote_addr 
    user_id = generate_user_id()
    
    with db_lock, sqlite3.connect('chat.db') as conn:
        try:
            c = conn.cursor()
            c.execute('INSERT INTO users (id, device_info, ip, last_active) VALUES (?, ?, ?, ?)',
                     (user_id, device_info, ip, time.time()))
            conn.commit()
            return jsonify({'status': 'success', 'id': user_id})
        except sqlite3.Error as e:
            return jsonify({'status': 'error', 'message': f'数据库错误: {str(e)}'}), 500 
 
@app.route('/verify_user', methods=['GET'])
def verify_user():
    user_id = request.args.get('user_id')
    if not user_id or len(user_id) != CONFIG['user_id_length']:
        return jsonify({'valid': False, 'message': 'Invalid user ID'}), 400 
    
    with db_lock, sqlite3.connect('chat.db') as conn:
        c = conn.cursor()
        c.execute('SELECT 1 FROM users WHERE id = ?', (user_id,))
        exists = c.fetchone() is not None 
    return jsonify({'valid': exists})
 
@app.route('/send', methods=['POST'])
def send_message():
    data = request.json 
    if not data or 'sender' not in data or 'text' not in data:
        return jsonify({'status': 'error', 'message': 'Invalid data'}), 400 
    
    try:
        sender_id = data['sender']
        text = data['text'].strip()
        if not text:
            return jsonify({'status': 'error', 'message': 'Message cannot be empty'}), 400 
        
        msg_time = datetime.now().strftime('%H:%M')
        timestamp = time.time()
        
        with db_lock, sqlite3.connect('chat.db') as conn:
            c = conn.cursor()
            c.execute('SELECT 1 FROM users WHERE id = ?', (sender_id,))
            if not c.fetchone():
                return jsonify({'status': 'error', 'message': 'User not registered'}), 401 
            
            c.execute('UPDATE users SET last_active = ? WHERE id = ?', 
                     (timestamp, sender_id))
            
            c.execute('INSERT INTO messages (sender, text, time, timestamp) VALUES (?, ?, ?, ?)',
                     (sender_id, text, msg_time, timestamp))
            conn.commit()
        
        return jsonify({'status': 'success', 'timestamp': timestamp})
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500 
 
@app.route('/get_history', methods=['GET'])
def get_history():
    user_id = request.args.get('user_id')
    if not user_id or len(user_id) != CONFIG['user_id_length']:
        return jsonify({'status': 'error', 'message': 'Invalid user ID', 'messages': []}), 400 
    
    try:
        with db_lock, sqlite3.connect('chat.db') as conn:
            conn.row_factory = sqlite3.Row 
            c = conn.cursor()
            c.execute('''SELECT sender, text, time, timestamp 
                         FROM messages 
                         WHERE sender = ? OR sender IN 
                            (SELECT id FROM users WHERE id != ?)
                         ORDER BY timestamp DESC 
                         LIMIT ?''', (user_id, user_id, CONFIG['message_cache_size']))
            messages = [dict(row) for row in c.fetchall()]
        
        messages.reverse()
        return jsonify({'status': 'success', 'messages': messages})
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e), 'messages': []}), 500 
 
@app.route('/get_new', methods=['GET'])
def get_new_messages():
    user_id = request.args.get('user_id')
    last_time = float(request.args.get('last_time', 0))
    
    if not user_id or len(user_id) != CONFIG['user_id_length']:
        return jsonify({'status': 'error', 'message': 'Invalid user ID', 'messages': []}), 400 
    
    try:
        with db_lock, sqlite3.connect('chat.db') as conn:
            conn.row_factory = sqlite3.Row 
            c = conn.cursor()
            c.execute('''SELECT sender, text, time, timestamp 
                         FROM messages 
                         WHERE timestamp > ? AND (sender = ? OR sender IN 
                            (SELECT id FROM users WHERE id != ?))
                         ORDER BY timestamp ASC''', 
                         (last_time/1000, user_id, user_id))
            messages = [dict(row) for row in c.fetchall()]
        
        return jsonify({'status': 'success', 'messages': messages})
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e), 'messages': []}), 500 
 
def run_server():
    init_db()
    ips = get_all_local_ips()
    print(" * 可用的服务器IP地址:")
    for ip in ips:
        print(f" * http://{ip}:{CONFIG['port']}")
    
    app.run(host='0.0.0.0', port=CONFIG['port'], debug=False, threaded=True)
 
if __name__ == '__main__':
    run_server()